using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

using ScreenSnapper;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace ScreenSnapper
{
    public partial class ScreenSnapper : Form
    {
        private HotKey _snapHotKeys;
        private bool _hasDisplayedFancyEffect = false;
        private bool _effectGoingUp = true;
        private bool _bFirstTime = true;
        private System.Windows.Forms.Timer _timer;
        private string _lastSnappedFile = null;
        private string _networkPeer = null;

        public string LastSnappedFile
        {
            get
            {
                return _lastSnappedFile;
            }
            set
            {
                _lastSnappedFile = value;
            }
        }
        public string NetworkPeer
        {
            get
            {
                return _networkPeer;
            }
            set
            {
                _networkPeer = value;
            }
        }

        private enum SnapMode
        {
            None = -1,
            Window = 0,
            Selection = 1,
            Clipboard = 2,
            Network = 3,
        }

        public ScreenSnapper()
        {
            InitializeComponent();

            int screenWidth = Screen.PrimaryScreen.WorkingArea.Width;
            int screenHeight = Screen.PrimaryScreen.WorkingArea.Height;

            int winWidth = ClientSize.Width;
            int winHeight = ClientSize.Height;

            Location = new Point(screenWidth - winWidth - 10, screenHeight - winHeight - 10);

            GraphicsPath gp = new GraphicsPath();
            int arc = 5;
            int w = winWidth - 1;
            int h = winHeight - 1;
            gp.AddArc(0, 0, arc * 2, arc * 2, 180, 90);
            gp.AddArc(w - arc * 2, 0, arc * 2, arc * 2, 270, 90);
            gp.AddArc(w - arc * 2, h - arc * 2, arc * 2, arc * 2, 0, 90);
            gp.AddArc(0, h - arc * 2, arc * 2, arc * 2, 90, 90);
            Region rg = new Region(gp);
            this.Region = rg;

            _snapHotKeys = new HotKey();
            _snapHotKeys.OwnerForm = this;
            _snapHotKeys.HotKeyPressed += new HotKey.HotKeyPressedEventHandler(HotKeyHandler);
            _snapHotKeys.AddHotKey(Keys.S, HotKey.MODKEY.MOD_WIN, "SnapWindowSelect");
            _snapHotKeys.AddHotKey(Keys.A, HotKey.MODKEY.MOD_WIN, "SnapWindowDirect");
            _snapHotKeys.AddHotKey(Keys.C, HotKey.MODKEY.MOD_WIN, "SnapClipboard");
            _snapHotKeys.AddHotKey(Keys.N, HotKey.MODKEY.MOD_WIN, "SnapNetwork");

            LoadSettings();
            if (enableNetworkServerToolStripMenuItem.Checked)
            {
                InitializeServerThread();
            }
        }

        private void InitializeServerThread()
        {
            // Launch server thread
            BitmapTcpServer.StartServer(this);
        }

        private void LoadSettings()
        {
            Object o = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "GoogleTalkMode", 2);
            int nGTalkMode = 2;
            if (null != o)
                nGTalkMode = (int)o;
            saveFileModeToolStripMenuItem.Checked = false;
            googleTalkModeToolStripMenuItem.Checked = false;
            completeImageDisplayModeToolStripMenuItem.Checked = false;
            switch (nGTalkMode)
            {
                case 2:
                    completeImageDisplayModeToolStripMenuItem.Checked = true;
                    break;
                case 1:
                    googleTalkModeToolStripMenuItem.Checked = true;
                    break;
                default:
                    saveFileModeToolStripMenuItem.Checked = true;
                    break;
            }

            o = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "ImageType", 0);
            int nImageType = 0;
            if (null != o)
                nImageType = (int)o;
            switch (nImageType)
            {
                case 0:
                    automaticToolStripMenuItem.Checked = true;
                    imageType_Click(automaticToolStripMenuItem, null);
                    break;
                case 2:
                    jpgToolStripMenuItem.Checked = true;
                    imageType_Click(jpgToolStripMenuItem, null);
                    break;
                case 1:
                default:
                    pngToolStripMenuItem.Checked = true;
                    imageType_Click(pngToolStripMenuItem, null);
                    break;
            }

            o = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "NetworkPeer", null);
            if (null != o)
            {
                NetworkPeer = (string)o;
            }

            o = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "StartNetworkServer", 0);
            int startNetworkServer = 0;
            if (o != null)
                startNetworkServer = (int)o;
            enableNetworkServerToolStripMenuItem.Checked = (startNetworkServer != 0);
        }

        private void SaveSettings()
        {
            int nMode = 0;
            if (googleTalkModeToolStripMenuItem.Checked)
                nMode = 1;
            else if (completeImageDisplayModeToolStripMenuItem.Checked)
                nMode = 2;
            Registry.SetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "GoogleTalkMode",
                nMode);
            int nImageType = 1;
            if (automaticToolStripMenuItem.Checked)
                nImageType = 0;
            else if (jpgToolStripMenuItem.Checked)
                nImageType = 2;
            Registry.SetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "ImageType", nImageType);
            Registry.SetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "Minimize", Visible ? 0 : 1);
            if (null != NetworkPeer)
                Registry.SetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "NetworkPeer", NetworkPeer);
        }

        private void snapButton_Click(object sender, EventArgs e)
        {
            DoSnap(SnapMode.Selection);
        }

        private void HotKeyHandler(string hotKeyId)
        {
            if (hotKeyId == "SnapWindowDirect")
            {
                DoSnap(SnapMode.Window);
            }
            else if (hotKeyId == "SnapClipboard")
            {
                DoSnap(SnapMode.Clipboard);
            }
            else if (hotKeyId == "SnapNetwork")
            {
                DoSnap(SnapMode.Network);
            }
            else
            {
                DoSnap(SnapMode.Selection);
            }
        }

        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        private void SaveJPGWithCompressionSetting(Image image, string szFileName, long lCompression)
        {
            EncoderParameters eps = new EncoderParameters(1);
            eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, lCompression);
            ImageCodecInfo ici = GetEncoderInfo("image/jpeg");
            image.Save(szFileName, ici, eps);
        }
        
        private string SaveImage(Image image, string strFileName)
        {
            string strWithoutExt = Path.GetFileNameWithoutExtension(strFileName);
            string strPath = Path.GetDirectoryName(strFileName);
            string strFile = strPath + "\\" + strWithoutExt;
            string strPngFileName = strFile + ".png";
            string strJpgFileName = strFile + ".jpg";
            string returnFileName = null;

            if (pngToolStripMenuItem.Checked)
            {
                image.Save(strPngFileName);
                returnFileName = strPngFileName;
            }
            else if (jpgToolStripMenuItem.Checked)
            {
                SaveJPGWithCompressionSetting(image, strJpgFileName, 75);
                returnFileName = strJpgFileName;
            }
            else // Automatic
            {
                image.Save(strPngFileName);
                SaveJPGWithCompressionSetting(image, strJpgFileName, 75);
                FileInfo fiPng = new FileInfo(strPngFileName);
                FileInfo fiJpg = new FileInfo(strJpgFileName);
                if (fiPng.Length > fiJpg.Length)
                {
                    File.Delete(strPngFileName);
                    returnFileName = strJpgFileName;
                }
                else
                {
                    File.Delete(strJpgFileName);
                    returnFileName = strPngFileName;
                }
            }

            LastSnappedFile = returnFileName;
            return returnFileName;
        }

        private void DoSnap(SnapMode snapMode)
        {
            Image image = null;
            Point point;

            if (SnapMode.Selection == snapMode)
            {
                BlankForm blankForm = new BlankForm();
                blankForm.ShowDialog(this);
                image = blankForm.SelectedImage;
                point = blankForm.TopLeft;
            }
            else if (SnapMode.Window == snapMode)
            {
                image = Fusion8Design.Win32.Desktop.GetForegroundWindowBitmap();
                point = new Point(30, 30);
            }
            else if (SnapMode.Network == snapMode)
            {
                image = GetImageFromNetwork();
                point = new Point(30, 30);
            }
            else
            {
                image = GetImageFromClipboard();
                point = new Point(30, 30);
            }
            
            if (null != image)
            {
                if (!googleTalkModeToolStripMenuItem.Checked && 
                    !completeImageDisplayModeToolStripMenuItem.Checked)
                {
                    DirInputDlg dlg = new DirInputDlg();
                    dlg.ShowDialog(this);
                    if (dlg.WasSaveClicked())
                    {
                        string strFileName = dlg.GetFileName();
                        //blankForm.SelectedImage.  Save(strFileName);
                        strFileName = SaveImage(image, strFileName);
                        Process.Start(dlg.GetPath());
                    }
                }
                else
                {
                    string strMyPicsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
                    string snapPath = strMyPicsPath + "\\Snapped";
                    if (!Directory.Exists(snapPath))
                        Directory.CreateDirectory(snapPath);
                    string tmpFileName = "snap_" + DateTime.Now.ToString("yyyy-MM-dd") + "_" + DateTime.Now.ToString("T") + ".png";
                    tmpFileName = tmpFileName.Replace(':', '-');
                    string tmpFilePath = snapPath + "\\" + tmpFileName;
                    //blankForm.SelectedImage.Save(tmpFilePath);
                    tmpFilePath = SaveImage(image, tmpFilePath);

                    bool bDisplayCompleteImage = completeImageDisplayModeToolStripMenuItem.Checked;
                    ImageDisplayForm idf = new ImageDisplayForm(point, image, tmpFilePath, bDisplayCompleteImage);
                    idf.Show(this);
                }
            } // if (image != null)
        }

        private Image GetImageFromNetwork()
        {
            BitmapTcpClient client = new BitmapTcpClient();
            if (null == NetworkPeer)
            {
                AskForNetworkPeer();
            }
            if (null == NetworkPeer)
            {
                return null;
            }
            BitmapTcpResponse response = client.FetchBitmapData(NetworkPeer);
            if (response == null ||
                response.ResponseType == BitmapTcpResponseType.None)
            {
                return null;
            }
            MemoryStream stream = new MemoryStream(response.Data);
            Image image = Image.FromStream(stream);
            return image;
        }

        private void AskForNetworkPeer()
        {
            string defaultValue = "";
            if (null != NetworkPeer)
                defaultValue = NetworkPeer;
            string networkPeer = SimpleStringInputDlg.ShowInputDialog(this, "Enter IP address for network images", defaultValue);
            if (null != networkPeer)
            {
                NetworkPeer = networkPeer;
            }
        }

        private Image GetImageFromClipboard()
        {
            Image image = null;
            try
            {
                image = Clipboard.GetImage();
            }
            catch (Exception ex)
            {
                string msg = ex.Message;
                MessageBox.Show(msg);
                // Ignore exceptions. Just return null (below).
            }

            return image;
        }

        private void closeButton_Click(object sender, EventArgs e)
        {
            Hide();
            notifyIcon.ShowBalloonTip(3000);
        }

        private void BigWindowMain_Activated(object sender, EventArgs e)
        {
            int nMinimize = 0;
            if (_bFirstTime)
            {
                Object o = Registry.GetValue("HKEY_CURRENT_USER\\Software\\Lexware\\ScreenSnapper", "Minimize", 0);
                if (null != o)
                    nMinimize = (int)o;
                _bFirstTime = false;
            }
            if (0 != nMinimize)
            {
                Hide();
            }
            else
            {
                if (!_hasDisplayedFancyEffect)
                {
                    _hasDisplayedFancyEffect = true;
                    Opacity = 0;
                    if (null != _timer)
                        _timer.Dispose();
                    _timer = null;
                    _timer = new System.Windows.Forms.Timer();
                    _timer.Tick += new EventHandler(ProcessTimerTick);
                    _timer.Interval = 25;
                    _timer.Start();
                }
            }
        }

        private void ProcessTimerTick(Object myObject, EventArgs myEventArgs)
        {
            double dOp = Opacity;
            if (dOp < 1.0 && _effectGoingUp)
            {
                Opacity += 0.1;
            }
            else
            {
                if (_effectGoingUp)
                {
                    Opacity = 0.975;
                    _effectGoingUp = false;
                }
                else if (dOp > 0.5)
                {
                    Opacity -= 0.025;
                }
                else
                {
                    _timer.Stop();
                }
            }
        }

        private void quitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveSettings();
            BitmapTcpServer.RequestExit();
            Close();
        }

        private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            Show();
            _hasDisplayedFancyEffect = false;
            _effectGoingUp = true;
            BigWindowMain_Activated(null, null);
        }

        private void BigWindowMain_Load(object sender, EventArgs e)
        {
            // ?
        }

        private void imageType_Click(object sender, EventArgs e)
        {
            if (sender == automaticToolStripMenuItem)
            {
                pngToolStripMenuItem.Checked = false;
                jpgToolStripMenuItem.Checked = false;

            }
            else if (sender == pngToolStripMenuItem)
            {
                automaticToolStripMenuItem.Checked = false;
                jpgToolStripMenuItem.Checked = false;
            }
            else if (sender == jpgToolStripMenuItem)
            {
                automaticToolStripMenuItem.Checked = false;
                pngToolStripMenuItem.Checked = false;
            }
        }

        private void snapMode_Click(object sender, EventArgs e)
        {
            if (sender != saveFileModeToolStripMenuItem)
                saveFileModeToolStripMenuItem.Checked = false;
            if (sender != googleTalkModeToolStripMenuItem)
                googleTalkModeToolStripMenuItem.Checked = false;
            if (sender != completeImageDisplayModeToolStripMenuItem)
                completeImageDisplayModeToolStripMenuItem.Checked = false;
        }

        private void networkPeerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AskForNetworkPeer();
        }

        private void enableNetworkServerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (enableNetworkServerToolStripMenuItem.Checked)
            {
                BitmapTcpServer.StartServer(this);
            }
            else
            {
                BitmapTcpServer.RequestExit();
            }
        }
    }
}
